home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 4
/
Aminet 4 - November 1994.iso
/
aminet
/
comm
/
net
/
dnet_src.lha
/
dnet
/
amiga
/
doshand
/
nfs-handler.c
< prev
Wrap
C/C++ Source or Header
|
1989-12-03
|
26KB
|
1,041 lines
/*
* NFS-HANDLER.C V1.11 27-June-89
*
* DNet DOS level NFS handler.
*
* By Matthew Dillon.
*
* This handler converts DOS packets into a form suitable for transmission
* over a DNet link to a remote server which will execute the operations.
*/
#include "dos.h"
#include <exec/alerts.h>
#define BTOC(bp) ((void *)(((long)bp) << 2))
#define CTOB(cp) ((BPTR)(((long)cp) >> 2))
/*
* Since this code might be called several times in a row without being
* unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!! This also goes
* for any global/static assignments that might be changed by running the
* code.
*/
PROC *DosProc; /* Our Process */
DEVNODE *DosNode; /* Our DOS node.. created by DOS for us */
DEVLIST *DevList; /* Device List structure for our volume node */
void *SysBase; /* EXEC library base */
/*
void *DResBase;
*/
DOSLIB *DOSBase; /* DOS library base for debug process */
MLIST FHBase; /* Open Files */
MLIST LCBase; /* Open Locks */
long TotalBytes; /* total bytes of data in filesystem */
void *CHan; /* DNet channel */
HANDLE RFRoot;
char TmpBuf[256];
#ifdef DEBUG
short DBDisable = 0; /* Debug code */
#endif
HANDLE *AllocHandle();
/*
* Don't call the entry point main(). This way, if you make a mistake
* with the compile options you'll get a link error.
*/
void __saveds noname ARGS((void));
void returnpacket ARGS((PACKET *));
int packetsqueued ARGS((void));
HANDLE *GetHandleForLock ARGS((LOCK *));
void *GetLockForHandle ARGS((HANDLE *));
HANDLE *AllocHandle ARGS((char *, RtOpen *));
void FreeHandle ARGS((HANDLE *));
void *dosalloc ARGS((ulong));
void dosfree ARGS((ulong *));
char *bstos ARGS((ubyte *));
char *skipdevice ARGS((char *));
int DoNetworkOp ARGS((char, void *, int, void *, int, void *, int));
void __saveds
noname()
{
PACKET *packet;
short error;
MSG *msg;
ubyte notdone;
void *tmp;
#ifndef LATTICE
mygeta4();
#endif
/*
* Initialize all global variables. SysBase MUST be initialized before
* we can make Exec calls.
*/
TotalBytes = 0;
SysBase = *(void **)4;
DOSBase = (void *)OpenLibrary("dos.library",0);
/*
DResBase= OpenLibrary("dres.library",0);
*/
DosProc = (PROC *)FindTask(NULL);
CHan = 0;
{
WaitPort(&DosProc->pr_MsgPort); /* Get Startup Packet */
msg = GetMsg(&DosProc->pr_MsgPort);
packet = (PACKET *)msg->mn_Node.ln_Name;
/*
* Loading DosNode->dn_Task causes DOS *NOT* to startup a new
* instance of the device driver for every reference. E.G. if
* you were writing a CON device you would want this field to
* be NULL.
*/
if (DOSBase /*&& DResBase*/) {
DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
DEVLIST *dl = dosalloc(sizeof(DEVLIST));
DosNode = BTOC(packet->dp_Arg3);
DosNode->dn_Task = &DosProc->pr_MsgPort;
/*
* Create Volume node and add to the device list. This will
* cause the WORKBENCH to recognize us as a disk. If we don't
* create a Volume node, Wb will not recognize us. However,
* we are a RAM: disk, Volume node or not.
*/
DevList = dl;
dl->dl_Type = DLT_VOLUME;
dl->dl_Task = &DosProc->pr_MsgPort;
dl->dl_DiskType = ID_DOS_DISK;
dl->dl_Name = (BSTR)DosNode->dn_Name;
dl->dl_Next = di->di_DevInfo;
di->di_DevInfo = (long)CTOB(dl);
packet->dp_Res1 = DOS_TRUE;
packet->dp_Res2 = 0;
} else { /* couldn't open dos.library */
packet->dp_Res1 = DOS_FALSE;
returnpacket(packet);
return; /* exit process */
}
returnpacket(packet);
}
/* Initialize RAM disk */
#ifdef DEBUG
dbinit();
#endif
{
NewList((LIST *)&FHBase); /* more globals */
NewList((LIST *)&LCBase);
BZero(&RFRoot, sizeof(RFRoot));
DateStamp(&RFRoot.Date);
RFRoot.Type = FILE_DIR;
RFRoot.Name = "Root";
}
/*
* Here begins the endless loop, waiting for requests over our
* message port and executing them. Since requests are sent over
* our message port, this precludes being able to call DOS functions
* ourselves (that is why the debugging routines are a separate process)
*/
top:
for (notdone = 1; notdone;) {
WaitPort(&DosProc->pr_MsgPort);
while (msg = GetMsg(&DosProc->pr_MsgPort)) {
packet = (PACKET *)msg->mn_Node.ln_Name;
packet->dp_Res1 = DOS_TRUE;
packet->dp_Res2 = 0;
error = 0;
if (!CHan) { /* attempt to open server channel */
CHan = DOpen(NULL, PORT_NFS, -80, -80);
if (!CHan) { /* otherwise giveup! */
notdone = 0;
goto fail;
}
}
#ifdef DEBUG
dbprintf("ACTION %ld\n", packet->dp_Type);
#endif
switch(packet->dp_Type) {
case ACTION_DIE: /* attempt to die? */
notdone = 0; /* try to die */
break;
case ACTION_OPENRW: /* FileHandle,Lock,Name Bool */
case ACTION_OPENOLD: /* FileHandle,Lock,Name Bool */
case ACTION_OPENNEW: /* FileHandle,Lock,Name Bool */
{
OpOpen opkt;
RtOpen rpkt;
short r;
char *name = skipdevice(bstos((ubyte *)packet->dp_Arg3));
HANDLE *handle;
opkt.DirHandle = GetHandleForLock((LOCK *)packet->dp_Arg2)->Handle;
opkt.Modes = packet->dp_Type;
r = DoNetworkOp('O',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt));
if (r) {
error = ERROR_OBJECT_IN_USE;
} else if (rpkt.Handle == -1) {
error = ERROR_OBJECT_NOT_FOUND;
} else if (rpkt.Type > 0) { /* can't open dir */
OpClose opkt;
opkt.Handle = rpkt.Handle;
DoNetworkOp('C',&opkt,sizeof(opkt),NULL,0,NULL,0);
error = ERROR_OBJECT_WRONG_TYPE;
} else {
if (name[0] == 0)
name = GetHandleForLock((LOCK *)packet->dp_Arg2)->Name;
handle = AllocHandle(name, &rpkt);
((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long)handle;
}
}
break;
case ACTION_READ: /* FHArg1,CPTRBuffer,Length ActLength */
{
HANDLE *handle = (HANDLE *)packet->dp_Arg1;
OpRead opkt;
RtRead rpkt;
short err;
opkt.Handle = handle->Handle;
opkt.Bytes = packet->dp_Arg3;
err = DoNetworkOp('R',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt));
if (err)
rpkt.Bytes = -1;
if (rpkt.Bytes > 0 && rpkt.Bytes <= opkt.Bytes)
DRead(CHan, (void *)packet->dp_Arg2, rpkt.Bytes);
packet->dp_Res1 = rpkt.Bytes;
}
break;
case ACTION_WRITE: /* FHArg1,CPTRBuffer,Length ActLength */
{
HANDLE *handle = (HANDLE *)packet->dp_Arg1;
OpWrite opkt;
RtWrite rpkt;
short err;
opkt.Handle = handle->Handle;
opkt.Bytes = packet->dp_Arg3;
err = DoNetworkOp('W',&opkt,sizeof(opkt),(void *)packet->dp_Arg2,packet->dp_Arg3,&rpkt,sizeof(rpkt));
if (err)
rpkt.Bytes = -1;
packet->dp_Res1 = rpkt.Bytes;
}
break;
case ACTION_CLOSE: /* FHArg1 Bool:TRUE */
{
HANDLE *handle = (HANDLE *)packet->dp_Arg1;
OpClose opkt;
if (packet->dp_Arg1 == NULL || handle->Magic != MAGIC) {
Alert(AT_Recovery|0, (char *)0x12345555);
} else {
opkt.Handle = handle->Handle;
DoNetworkOp('C',&opkt,sizeof(opkt),NULL,0,NULL,0);
FreeHandle(handle);
}
}
if (!GetHead(&FHBase))
notdone = 0;
break;
case ACTION_SEEK: /* FHArg1,Position,Mode OldPosition*/
{
HANDLE *handle = (HANDLE *)packet->dp_Arg1;
OpSeek opkt;
RtSeek rpkt;
short err;
opkt.Handle = handle->Handle;
opkt.Offset = packet->dp_Arg2;
opkt.How = packet->dp_Arg3 + 1;
err = DoNetworkOp('S',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt));
if (err)
rpkt.NewOffset = -1;
if (rpkt.NewOffset < 0)
error = ERROR_SEEK_ERROR;
else
packet->dp_Res1 = rpkt.OldOffset;
}
break;
case ACTION_EXAMINE_NEXT: /* Lock,Fib Bool */
{
HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1);
FIB *fib = BTOC(packet->dp_Arg2);
OpNextDir opkt;
RtNextDir rpkt;
short err;
#ifdef DEBUG
dbprintf("FIB = %08lx\n", fib);
#endif
if (handle->Type < 0) {
error = ERROR_OBJECT_WRONG_TYPE;
break;
}
opkt.Handle = handle->Handle;
opkt.Index = fib->fib_DiskKey;
err = DoNetworkOp('N',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt));
if (err || rpkt.Handle == -1) {
error = ERROR_NO_MORE_ENTRIES;
} else { /* not a real file handle, just info & name */
unsigned char fn;
if (DRead(CHan, &fn, 1) != 1)
TmpBuf[fn = 0] = 0;
if (DRead(CHan, TmpBuf, fn) != fn)
TmpBuf[fn = 0] = 0;
++fib->fib_DiskKey; /* next key */
fib->fib_DirEntryType = rpkt.Type;
fib->fib_Protection = rpkt.Prot;
fib->fib_EntryType = NULL;
fib->fib_Size = rpkt.Size;
fib->fib_NumBlocks = rpkt.Size >> 9;
if (strlen(TmpBuf) >= sizeof(fib->fib_FileName) - 2) {
fib->fib_FileName[0] = 1;
fib->fib_FileName[1] = '?';
fib->fib_FileName[2] = 0;
} else {
strcpy(fib->fib_FileName+1, TmpBuf);
fib->fib_FileName[0] = strlen(TmpBuf);
}
fib->fib_Comment[0] = 0;
fib->fib_Comment[1] = 0;
fib->fib_Date = rpkt.Date;
}
}
break;
case ACTION_EXAMINE_OBJECT: /* Lock,Fib Bool */
{
HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1);
FIB *fib = BTOC(packet->dp_Arg2);
#ifdef DEBUG
dbprintf("FIB = %08lx\n", fib);
#endif
fib->fib_DiskKey = 0;
fib->fib_DirEntryType = handle->Type;
/*
* fib->fib_FileName bcpl type string
*/
fib->fib_Protection = handle->Prot;
fib->fib_EntryType = NULL;
fib->fib_Size = handle->Size;
fib->fib_NumBlocks = handle->Size >> 9;
if (strlen(handle->Name) >= sizeof(fib->fib_FileName) - 2) {
fib->fib_FileName[0] = 1;
fib->fib_FileName[1] = '?';
fib->fib_FileName[2] = 0;
} else {
strcpy(fib->fib_FileName+1, handle->Name);
fib->fib_FileName[0] = strlen(handle->Name);
}
fib->fib_Comment[0] = 0;
fib->fib_Comment[1] = 0;
fib->fib_Date = handle->Date;
}
break;
case ACTION_INFO: /* Lock, InfoData Bool:TRUE */
tmp = BTOC(packet->dp_Arg2);
error = -1;
/* fall through */
case ACTION_DISK_INFO: /* InfoData Bool:TRUE */
{
INFODATA *id;
/*
* Note: id_NumBlocks is never 0, but only to get
* around a bug I found in my shell (where I divide
* by id_NumBlocks). Other programs probably break
* as well.
*/
(error) ? (id = tmp) : (id = BTOC(packet->dp_Arg1));
error = 0;
BZero(id, sizeof(*id));
id->id_DiskState = ID_VALIDATED;
id->id_NumBlocks = (TotalBytes >> 9) + 1;
id->id_NumBlocksUsed = (TotalBytes >> 9) + 1;
id->id_BytesPerBlock = 512;
id->id_DiskType = ID_DOS_DISK;
id->id_VolumeNode = (long)CTOB(DosNode);
id->id_InUse = (long)GetHead(&LCBase);
}
break;
case ACTION_PARENT: /* Lock ParentLock */
{
HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1);
OpParent opkt;
RtParent rpkt;
short err;
opkt.Handle = handle->Handle;
err = DoNetworkOp('P',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt));
if (err)
rpkt.Handle = NULL;
if (rpkt.Handle == -1) {
error = ERROR_OBJECT_NOT_FOUND;
} else { /* create a file handle and return a lock */
HANDLE *newhandle;
unsigned char fn;
if (DRead(CHan, &fn, 1) != 1)
TmpBuf[fn = 0] = 0;
if (DRead(CHan, TmpBuf, fn) != fn)
TmpBuf[fn = 0] = 0;
newhandle = AllocHandle(TmpBuf, &rpkt);
packet->dp_Res1 = (long)GetLockForHandle(newhandle);
}
}
break;
case ACTION_DELETE_OBJECT: /*Lock,Name Bool */
{
OpDelete opkt;
RtDelete rpkt;
short err;
char *name = skipdevice(bstos((ubyte *)packet->dp_Arg2));
opkt.DirHandle = GetHandleForLock((LOCK *)packet->dp_Arg1)->Handle;
err = DoNetworkOp('D',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt));
if (err || rpkt.Error)
error = ERROR_OBJECT_NOT_FOUND;
}
break;
case ACTION_CREATE_DIR: /* Lock,Name Lock */
{
OpCreateDir opkt;
RtCreateDir rpkt;
short err;
char *name = skipdevice(bstos((ubyte *)packet->dp_Arg2));
opkt.DirHandle = GetHandleForLock((LOCK *)packet->dp_Arg1)->Handle;
err = DoNetworkOp('M',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt));
if (err)
rpkt.Handle = NULL;
if (rpkt.Handle == -1) {
error = ERROR_OBJECT_EXISTS;
} else { /* create a file handle and return a lock */
HANDLE *newhandle = AllocHandle(name, &rpkt);
packet->dp_Res1 = (long)GetLockForHandle(newhandle);
}
}
break;
case ACTION_LOCATE_OBJECT: /* Lock,Name,Mode Lock */
{
OpOpen opkt;
RtOpen rpkt;
short err;
char *name = skipdevice(bstos((ubyte *)packet->dp_Arg2));
HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1);
opkt.DirHandle = handle->Handle;
opkt.Modes = 1005;
err = DoNetworkOp('O',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt));
if (err) {
error = ERROR_OBJECT_IN_USE;
} else if (rpkt.Handle == -1) {
error = ERROR_OBJECT_NOT_FOUND;
} else {
HANDLE *newhandle;
if (name[0] == 0)
name = handle->Name;
newhandle = AllocHandle(name, &rpkt);
packet->dp_Res1 = (long)GetLockForHandle(newhandle);
}
}
break;
case ACTION_COPY_DIR: /* Lock, Lock */
{
OpDup opkt;
RtDup rpkt;
short err;
HANDLE *oldhandle = GetHandleForLock((LOCK *)packet->dp_Arg1);
opkt.Handle = oldhandle->Handle;
err = DoNetworkOp('d',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt));
if (err) {
error = ERROR_OBJECT_IN_USE;
} else if (rpkt.Handle == -1) {
error = ERROR_OBJECT_NOT_FOUND;
} else {
HANDLE *handle = AllocHandle(oldhandle->Name, &rpkt);
packet->dp_Res1 = (long)GetLockForHandle(handle);
}
}
break;
case ACTION_FREE_LOCK: /* Lock, Bool */
{
HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1);
OpClose opkt;
opkt.Handle = handle->Handle;
DoNetworkOp('C',&opkt,sizeof(opkt),NULL,0,NULL,0);
FreeHandle(handle);
}
break;
case ACTION_SET_PROTECT:/* -,Lock,Name,Mask Bool */
error = ERROR_ACTION_NOT_KNOWN;
break;
case ACTION_SET_COMMENT:/* -,Lock,Name,Comment Bool */
error = ERROR_ACTION_NOT_KNOWN;
break;
case ACTION_RENAME_OBJECT:/* SLock,SName,DLock,DName Bool */
{
OpRename opkt;
RtRename rpkt;
short err;
char *name1= skipdevice(bstos((ubyte *)packet->dp_Arg2));
char *name2= skipdevice(bstos((ubyte *)packet->dp_Arg4));
short len1 = strlen(name1);
short len2 = strlen(name2);
char *name = AllocMem(len1+len2+2, MEMF_PUBLIC);
opkt.DirHandle1 = GetHandleForLock((LOCK *)packet->dp_Arg1)->Handle;
opkt.DirHandle2 = GetHandleForLock((LOCK *)packet->dp_Arg3)->Handle;
strcpy(name, name1);
strcpy(name+len1+1,name2);
err = DoNetworkOp('r',&opkt,sizeof(opkt),name,len1+len2+2,&rpkt,sizeof(rpkt));
FreeMem(name, len1+len2+2);
if (err) {
error = ERROR_OBJECT_IN_USE;
} else if (rpkt.Error) {
error = ERROR_OBJECT_NOT_FOUND;
}
}
break;
/*
* A few other packet types which we do not support
*/
case ACTION_INHIBIT: /* Bool Bool */
/* Return success for the hell of it */
break;
case ACTION_RENAME_DISK:/* BSTR:NewName Bool */
case ACTION_MORECACHE: /* #BufsToAdd Bool */
case ACTION_WAIT_CHAR: /* Timeout, ticks Bool */
case ACTION_FLUSH: /* writeout bufs, disk motor off */
case ACTION_RAWMODE: /* Bool(-1:RAW 0:CON) OldState */
default:
fail:
error = ERROR_ACTION_NOT_KNOWN;
break;
}
if (packet) {
if (error) {
packet->dp_Res1 = DOS_FALSE;
packet->dp_Res2 = error;
}
returnpacket(packet);
}
}
}
Delay(50); /* I wanna even see the debug message! */
Forbid();
if (packetsqueued() || GetHead(&FHBase)) {
Permit();
goto top; /* sorry... can't exit */
}
/*
* Causes a new process to be created on next reference
*/
DosNode->dn_Task = FALSE;
/*
* Remove Volume entry. Since DOS uses singly linked lists, we
* must (ugg) search it manually to find the link before our
* Volume entry.
*/
{
DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info);
DEVLIST *dl;
void *dlp;
dlp = &di->di_DevInfo;
for (dl = BTOC(di->di_DevInfo); dl && dl != DevList; dl = BTOC(dl->dl_Next))
dlp = &dl->dl_Next;
if (dl == DevList) {
*(BPTR *)dlp = dl->dl_Next;
dosfree((ulong *)dl);
} else {
;
}
}
/*
* closedown, fall of the end of the world
*
* (which is how you kill yourself if a PROCESS. A TASK would have
* had to RemTask(NULL) itself).
*/
if (CHan)
DClose(CHan);
CHan = 0;
#ifdef DEBUG
dbuninit();
#endif
CloseLibrary((LIB *)DOSBase);
/*
CloseLibrary(DResBase);
*/
}
/*
* PACKET ROUTINES. Dos Packets are in a rather strange format as you
* can see by this and how the PACKET structure is extracted in the
* GetMsg() of the main routine.
*/
void
returnpacket(packet)
PACKET *packet;
{
struct Message *mess;
struct MsgPort *replyport;
replyport = packet->dp_Port;
mess = packet->dp_Link;
packet->dp_Port = &DosProc->pr_MsgPort;
mess->mn_Node.ln_Name = (char *)packet;
mess->mn_Node.ln_Succ = NULL;
mess->mn_Node.ln_Pred = NULL;
PutMsg(replyport, mess);
}
/*
* Are there any packets queued to our device?
*/
int
packetsqueued()
{
return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head !=
(void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail);
}
/*
* Handle structure, locks, and manipulation.
*/
HANDLE *
GetHandleForLock(block)
LOCK *block;
{
LOCK *lock = BTOC(block);
HANDLE *handle;
#ifdef DEBUG
dbprintf("GetHandleForLock: %08lx ", lock);
#endif
if (lock) {
handle = (HANDLE *)lock->fl_Key;
#ifdef DEBUG
dbprintf("Handle=%08lx (h=$%08lx)\n", handle, handle->Handle);
#endif
if (handle->Magic == MAGIC)
return(handle);
Alert(AT_Recovery|1, (char *)handle);
}
#ifdef DEBUG
dbprintf("\n");
#endif
/*Alert(AT_Recovery|2, (char *)-2);*/
return(&RFRoot);
}
void *
GetLockForHandle(handle)
HANDLE *handle;
{
LOCK *lock = handle->Lock;
LOCKLINK *ln;
#ifdef DEBUG
dbprintf("GetLockForHandle: %08lx ", handle);
#endif
if (!lock) {
lock = dosalloc(sizeof(LOCK));
#ifdef DEBUG
dbprintf("(allocate) %08lx\n", lock);
#endif
ln = AllocMem(sizeof(LOCKLINK), MEMF_PUBLIC|MEMF_CLEAR);
AddHead((LIST *)&LCBase,(NODE *)ln);
ln->Lock = lock;
lock->fl_Link = (long)ln;
lock->fl_Key = (long)handle;
lock->fl_Access = ACCESS_READ;
lock->fl_Task= &DosProc->pr_MsgPort;
lock->fl_Volume = (BPTR)CTOB(DosNode);
handle->Lock = lock;
}
#ifdef DEBUG
dbprintf("Lock=%08lx\n", lock);
#endif
return((void *)CTOB(lock));
}
HANDLE *
AllocHandle(name, rpkt)
char *name;
RtOpen *rpkt;
{
HANDLE *handle;
char *ptr;
for (ptr = name + strlen(name) - 1; ptr >= name && *ptr != '/'; --ptr);
++ptr;
handle = AllocMem(sizeof(HANDLE), MEMF_PUBLIC|MEMF_CLEAR);
handle->Magic = MAGIC;
handle->Handle= rpkt->Handle;
handle->Type = rpkt->Type;
handle->Prot = rpkt->Prot;
handle->Size = rpkt->Size;
handle->Name = AllocMem(strlen(ptr)+1, MEMF_PUBLIC);
handle->Date = rpkt->Date;
strcpy(handle->Name, ptr);
AddHead((LIST *)&FHBase, (NODE *)handle);
#ifdef DEBUG
dbprintf("AllocHandle: %08lx '%s' h=$%08lx\n", handle, ptr, handle->Handle);
#endif
return(handle);
}
void
FreeHandle(handle)
HANDLE *handle;
{
#ifdef DEBUG
dbprintf("FreeHandle: %08lx %08lx\n", handle, handle->Lock);
#endif
if (handle->Lock) {
LOCK *lock = handle->Lock;
Remove((NODE *)lock->fl_Link);
FreeMem((void *)lock->fl_Link, sizeof(LOCKLINK));
dosfree((ulong *)lock);
}
Remove((NODE *)handle);
handle->Magic = 0;
FreeMem(handle->Name, strlen(handle->Name)+1);
FreeMem(handle, sizeof(HANDLE));
}
/*
* DOS MEMORY ROUTINES
*
* DOS makes certain assumptions about LOCKS. A lock must minimally be
* a FileLock structure, with additional private information after the
* FileLock structure. The longword before the beginning of the structure
* must contain the length of structure + 4.
*
* NOTE!!!!! The workbench does not follow the rules and assumes it can
* copy lock structures. This means that if you want to be workbench
* compatible, your lock structures must be EXACTLY sizeof(struct FileLock).
*/
void *
dosalloc(bytes)
ulong bytes;
{
ulong *ptr;
bytes += 4;
ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR);
*ptr = bytes;
return(ptr+1);
}
void
dosfree(ptr)
ulong *ptr;
{
--ptr;
FreeMem(ptr, *ptr);
}
/*
* Convert a BSTR into a normal string.. copying the string into buf.
* I use normal strings for internal storage, and convert back and forth
* when required.
*/
char *
bstos(bstr)
ubyte *bstr;
{
static char buf[512];
static char *ptr = buf;
if (ptr == buf) /* switch which buffer to use */
ptr = buf + 256;
else
ptr = buf;
bstr = BTOC(bstr);
BMov(bstr+1,ptr,*bstr);
ptr[*bstr] = 0;
return(ptr);
}
char *
skipdevice(str)
char *str;
{
char *base = str;
while (*str && *str != ':')
++str;
if (*str == 0)
str = base;
else
++str;
return(str);
}
/*
* data = DoNetworkOp(&cmd, &len, data)
*/
int
DoNetworkOp(cmd, s, _slen, d, dlen, r, rlen)
char cmd;
int _slen;
void *s;
void *d;
void *r;
{
ubyte slen = _slen;
if (CHan) {
if (DWrite(CHan, &cmd, 1) < 0)
goto fail;
if (DWrite(CHan, &slen, 1) < 0)
goto fail;
if (DWrite(CHan, &dlen, 4) < 0)
goto fail;
if (DWrite(CHan, s, slen) < 0)
goto fail;
if (dlen) {
if (DWrite(CHan, d, dlen) < 0)
goto fail;
}
if (r) {
if (DRead(CHan, r, rlen) != rlen)
goto fail;
}
return(0);
}
fail:
if (CHan) {
DClose(CHan);
CHan = 0;
}
return(1);
}
#ifndef LATTICE
#asm
_mygeta4:
far data
lea __H1_org+32766,a4
rts
public __H0_org
dseg
public __H1_org
cseg
#endasm
#endif
#ifdef DEBUG /* note, doesn't work w/ Lattice */
/*
* DEBUG CODE
*/
/* DEBUGGING */
PORT *Dbport; /* owned by the debug process */
PORT *Dback; /* owned by the DOS device driver */
MSG DummyMsg; /* Dummy message that debug proc can use */
/*
* DEBUGGING CODE. You cannot make DOS library calls that access other
* devices from within a DOS device driver because they use the same
* message port as the driver. If you need to make such calls you must
* create a port and construct the DOS messages yourself. I do not
* do this. To get debugging info out another PROCESS is created to which
* debugging messages can be sent.
*
* You want the priority of the debug process to be larger than the
* priority of your DOS handler. This is so if your DOS handler crashes
* you have a better idea of where it died from the debugging messages
* (remember that the two processes are asyncronous from each other).
*/
extern void debugproc();
dbinit()
{
TASK *task = FindTask(NULL);
Dback = CreatePort(NULL,NULL);
CreateProc("DEV_DB", task->tc_Node.ln_Pri+1, CTOB(debugproc), 4096);
WaitPort(Dback); /* handshake startup */
GetMsg(Dback); /* remove dummy msg */
dbprintf("Debugger running V1.10, 2 November 1987\n");
dbprintf("Works with WORKBENCH!\n");
}
dbuninit()
{
MSG killmsg;
if (Dbport) {
killmsg.mn_Length = 0; /* 0 means die */
PutMsg(Dbport,&killmsg);
WaitPort(Dback); /* He's dead jim! */
GetMsg(Dback);
DeletePort(Dback);
/*
* Since the debug process is running at a greater priority, I
* am pretty sure that it is guarenteed to be completely removed
* before this task gets control again. Still, it doesn't hurt...
*/
Delay(50); /* ensure he's dead */
}
}
dbprintf(a,b,c,d,e,f,g,h,i,j)
{
char buf[256];
MSG *msg;
if (Dbport && !DBDisable) {
sprintf(buf,a,b,c,d,e,f,g,h,i,j);
msg = AllocMem(sizeof(MSG)+strlen(buf)+1, MEMF_PUBLIC|MEMF_CLEAR);
msg->mn_Length = strlen(buf)+1; /* Length NEVER 0 */
strcpy(msg+1,buf);
PutMsg(Dbport,msg);
}
}
/*
* BTW, the DOS library used by debugmain() was actually openned by
* the device driver. Note: DummyMsg cannot be on debugmain()'s stack
* since debugmain() goes away on the final handshake.
*/
void
debugmain()
{
MSG *msg;
short len;
void *fh;
mygeta4();
Dbport = CreatePort(NULL,NULL);
fh = Open("con:0/0/640/100/debugwindow", 1006);
PutMsg(Dback, &DummyMsg);
for (;;) {
WaitPort(Dbport);
msg = GetMsg(Dbport);
len = msg->mn_Length;
if (len == 0)
break;
--len; /* Fix length up */
Write(fh, msg+1, len);
FreeMem(msg,sizeof(MSG)+len+1);
}
Close(fh);
DeletePort(Dbport);
PutMsg(Dback,&DummyMsg); /* Kill handshake */
}
/*
* The assembly tag for the DOS process: CNOP causes alignment problems
* with the Aztec assembler for some reason. I assume then, that the
* alignment is unknown. Since the BCPL conversion basically zero's the
* lower two bits of the address the actual code may start anywhere around
* the label.... Sigh.... (see CreatProc() above).
*/
#asm
public _debugproc
public _debugmain
cseg
nop
nop
nop
_debugproc:
nop
nop
movem.l D2-D7/A2-A6,-(sp)
jsr _debugmain
movem.l (sp)+,D2-D7/A2-A6
rts
#endasm
#endif